/*
 * Copyright (c) 2023 iQi.Co.Ltd. All rights reserved.
 */
 
using System.Collections.Generic;
using NetProtocol.POD;
using NetProtocol.Enum;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.GamePlay;
using IQIGame.Onigao.Framework;
using System.Threading.Tasks;
using System;

namespace NetProtocol.Server {
	/// <summary>
	/// 逻辑服连接模块
	/// module : logicServer
	/// </summary>
	public interface SNetLogicServer : INetServerModule {
		Dictionary<int, MessageHandler> INetServerModule.GetModuleFunction()
        {	
            return new()
            {
                { NetMessageId.logicServer_connect, (session, data) =>
		            {
#if ENABLE_NET_LOG || UNITY_EDITOR
						NetProtocolHelper.ServerLog(NetMessageId.logicServer_connect, "Recv->" + data.ToString());
#endif
		                ConnectRequest _data = (ConnectRequest)data;
						return CS_connect(session, _data.token, _data.logicServerId, _data.gameServerId);
		            } 
            	},
                { NetMessageId.logicServer_reconnect, (session, data) =>
		            {
#if ENABLE_NET_LOG || UNITY_EDITOR
						NetProtocolHelper.ServerLog(NetMessageId.logicServer_reconnect, "Recv->" + data.ToString());
#endif
		                ReconnectRequest _data = (ReconnectRequest)data;
						return CS_reconnect(session, _data.reconnectToken, _data.readMsgCount, _data.connectId);
		            } 
            	},
                { NetMessageId.logicServer_ping, (session, data) =>
		            {
#if ENABLE_NET_LOG || UNITY_EDITOR
						NetProtocolHelper.ServerLog(NetMessageId.logicServer_ping, "Recv->" + data.ToString());
#endif
		                PingRequest _data = (PingRequest)data;
		                CS_ping(session);
		                return VoidMessageResult.Instance;
		            } 
            	},
                { NetMessageId.logicServer_logout, (session, data) =>
		            {
#if ENABLE_NET_LOG || UNITY_EDITOR
						NetProtocolHelper.ServerLog(NetMessageId.logicServer_logout, "Recv->" + data.ToString());
#endif
		                LogoutRequest _data = (LogoutRequest)data;
						return CS_logout(session);
		            } 
            	},
            };
        }
        
        Dictionary<int, Func<IReceiveMessage>> INetServerModule.GetModuleRequest() 
        {
	        return new ()
	        {
	        	{NetMessageId.logicServer_connect, ()=> new ConnectRequest()},
	        	{NetMessageId.logicServer_reconnect, ()=> new ReconnectRequest()},
	        	{NetMessageId.logicServer_ping, ()=> new PingRequest()},
	        	{NetMessageId.logicServer_logout, ()=> new LogoutRequest()},
	        };
	    }
        
#region Server-side Interface
		/// <summary>
        /// 连接服务器
        /// </summary>
	    protected ConnectResult CS_connect(ISession session, string token, string logicServerId, string gameServerId);
		/// <summary>
        /// 重连服务器
        /// </summary>
	    protected ReconnectResult CS_reconnect(ISession session, string reconnectToken, int readMsgCount, string connectId);
		/// <summary>
        /// 心跳
        /// </summary>
    	protected bool CS_ping(ISession session);
		/// <summary>
        /// 登出
        /// </summary>
	    protected LogoutResult CS_logout(ISession session);
#endregion
#region Client-side Interface
		/// <summary>
        /// connectId=连接id,用于断线重连
        /// </summary>
        public ConnectResult SC_connectResult(Task<ConnectResult> future){return new ConnectResult(future);}
        public ConnectResult SC_connectResult(int code, string reconnectToken, string connectId){return new ConnectResult(code, reconnectToken, connectId);}
        public ConnectResult SC_connectResult(int code){return new ConnectResult(code);}
		/// <summary>
        /// 
        /// </summary>
        public ReconnectResult SC_reconnectResult(Task<ReconnectResult> future){return new ReconnectResult(future);}
        public ReconnectResult SC_reconnectResult(int code, int lastMsgOrder, string reconnectToken, string connectId){return new ReconnectResult(code, lastMsgOrder, reconnectToken, connectId);}
        public ReconnectResult SC_reconnectResult(int code){return new ReconnectResult(code);}
		/// <summary>
        /// 心跳回执
        /// </summary>
		public bool SC_pang(ISession session, long serverTime){
	        return NetProtocolHelper.SendMessage(session, new Pang(serverTime));
	    }
	    public void SC_pang_Broadcast(List<ISession> sessions, long serverTime){
	        NetProtocolHelper.BroadcastMessage(sessions, new Pang(serverTime));
	    }
		/// <summary>
        /// 登出
        /// </summary>
        public LogoutResult SC_logoutResult(Task<LogoutResult> future){return new LogoutResult(future);}
        public LogoutResult SC_logoutResult(int code){return new LogoutResult(code);}
		/// <summary>
        /// 通知系统状态
        /// </summary>
		public bool SC_notifyServerStatus(ISession session, long time, int rawOffset, bool testMode){
	        return NetProtocolHelper.SendMessage(session, new NotifyServerStatus(time, rawOffset, testMode));
	    }
	    public void SC_notifyServerStatus_Broadcast(List<ISession> sessions, long time, int rawOffset, bool testMode){
	        NetProtocolHelper.BroadcastMessage(sessions, new NotifyServerStatus(time, rawOffset, testMode));
	    }
		/// <summary>
        /// 通用错误通知,包括被其他人登陆通知
        /// </summary>
		public bool SC_notifyError(ISession session, int code, string msg){
	        return NetProtocolHelper.SendMessage(session, new NotifyError(code, msg));
	    }
	    public void SC_notifyError_Broadcast(List<ISession> sessions, int code, string msg){
	        NetProtocolHelper.BroadcastMessage(sessions, new NotifyError(code, msg));
	    }
		/// <summary>
        /// 通知下线, 客户端不要进行重连
        /// </summary>
		public bool SC_notifyOffline(ISession session){
	        return NetProtocolHelper.SendMessage(session, new NotifyOffline());
	    }
	    public void SC_notifyOffline_Broadcast(List<ISession> sessions){
	        NetProtocolHelper.BroadcastMessage(sessions, new NotifyOffline());
	    }
#endregion

#region Messages
	public class ConnectResult : MessageResult {
	    private string reconnectToken;
	    private string connectId;
	    public ConnectResult(Task<ConnectResult> future): base(future) { }
		public ConnectResult(int code): base(code) { }
		public new ConnectResult SetDelayCall(Action delayCall) { base.SetDelayCall(delayCall); return this; }
	    internal ConnectResult(int code, string reconnectToken, string connectId){
	        this.code = code;
	        this.reconnectToken = reconnectToken;
	        this.connectId = connectId;
	    }
        public override MessageResult GetFutureResult(Task task) { return ((Task<ConnectResult>)task).Result; }
		public override int GetMessageId() {return NetMessageId.logicServer_connectResult;}
		public override SendPackage ToPackage() {
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_connectResult;
			si_p.StartWrite();
			SOutputStream _out = si_p.OutputStream;
			_out.Write_int(code);
			_out.Write_string(reconnectToken);
			_out.Write_string(connectId);
			return si_p;
		}
		public override string ToString() {
    		return "LogicServer.SC_connectResult { "
			+ "code="
			+ code
			+ ", reconnectToken="
			+ reconnectToken
			+ ", connectId="
			+ connectId
			+" }";
		}
	}
	public class ReconnectResult : MessageResult {
	    private int lastMsgOrder;
	    private string reconnectToken;
	    private string connectId;
	    public ReconnectResult(Task<ReconnectResult> future): base(future) { }
		public ReconnectResult(int code): base(code) { }
		public new ReconnectResult SetDelayCall(Action delayCall) { base.SetDelayCall(delayCall); return this; }
	    internal ReconnectResult(int code, int lastMsgOrder, string reconnectToken, string connectId){
	        this.code = code;
	        this.lastMsgOrder = lastMsgOrder;
	        this.reconnectToken = reconnectToken;
	        this.connectId = connectId;
	    }
        public override MessageResult GetFutureResult(Task task) { return ((Task<ReconnectResult>)task).Result; }
		public override int GetMessageId() {return NetMessageId.logicServer_reconnectResult;}
		public override SendPackage ToPackage() {
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_reconnectResult;
			si_p.StartWrite();
			SOutputStream _out = si_p.OutputStream;
			_out.Write_int(code);
			_out.Write_int(lastMsgOrder);
			_out.Write_string(reconnectToken);
			_out.Write_string(connectId);
			return si_p;
		}
		public override string ToString() {
    		return "LogicServer.SC_reconnectResult { "
			+ "code="
			+ code
			+ ", lastMsgOrder="
			+ lastMsgOrder
			+ ", reconnectToken="
			+ reconnectToken
			+ ", connectId="
			+ connectId
			+" }";
		}
	}
	public class Pang : MessageNotify {
		private long serverTime;
		public Pang(long serverTime) {
		    this.serverTime = serverTime;
		}
		public override int GetMessageId() {return NetMessageId.logicServer_pang;}
		public override SendPackage ToPackage() {
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_pang;
			si_p.StartWrite();
			SOutputStream _out = si_p.OutputStream;
			_out.Write_long(serverTime);
			return si_p;
		}
		public override string ToString() {
			return "LogicServer.SC_pang { "
			+ "serverTime="
			+ serverTime
			+" }";
		}
	}
	public class LogoutResult : MessageResult {
	    public LogoutResult(Task<LogoutResult> future): base(future) { }
		public LogoutResult(int code): base(code) { }
		public new LogoutResult SetDelayCall(Action delayCall) { base.SetDelayCall(delayCall); return this; }
        public override MessageResult GetFutureResult(Task task) { return ((Task<LogoutResult>)task).Result; }
		public override int GetMessageId() {return NetMessageId.logicServer_logoutResult;}
		public override SendPackage ToPackage() {
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_logoutResult;
			si_p.StartWrite();
			SOutputStream _out = si_p.OutputStream;
			_out.Write_int(code);
			return si_p;
		}
		public override string ToString() {
    		return "LogicServer.SC_logoutResult { "
			+ "code="
			+ code
			+" }";
		}
	}
	public class NotifyServerStatus : MessageNotify {
		private long time;
		private int rawOffset;
		private bool testMode;
		public NotifyServerStatus(long time, int rawOffset, bool testMode) {
		    this.time = time;
		    this.rawOffset = rawOffset;
		    this.testMode = testMode;
		}
		public override int GetMessageId() {return NetMessageId.logicServer_notifyServerStatus;}
		public override SendPackage ToPackage() {
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_notifyServerStatus;
			si_p.StartWrite();
			SOutputStream _out = si_p.OutputStream;
			_out.Write_long(time);
			_out.Write_int(rawOffset);
			_out.Write_boolean(testMode);
			return si_p;
		}
		public override string ToString() {
			return "LogicServer.SC_notifyServerStatus { "
			+ "time="
			+ time
			+ ", rawOffset="
			+ rawOffset
			+ ", testMode="
			+ testMode
			+" }";
		}
	}
	public class NotifyError : MessageNotify {
		private int code;
		private string msg;
		public NotifyError(int code, string msg) {
		    this.code = code;
		    this.msg = msg;
		}
		public override int GetMessageId() {return NetMessageId.logicServer_notifyError;}
		public override SendPackage ToPackage() {
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_notifyError;
			si_p.StartWrite();
			SOutputStream _out = si_p.OutputStream;
			_out.Write_int(code);
			_out.Write_string(msg);
			return si_p;
		}
		public override string ToString() {
			return "LogicServer.SC_notifyError { "
			+ "code="
			+ code
			+ ", msg="
			+ msg
			+" }";
		}
	}
	public class NotifyOffline : MessageNotify {
		public NotifyOffline() {
		}
		public override int GetMessageId() {return NetMessageId.logicServer_notifyOffline;}
		public override SendPackage ToPackage() {
			SendPackage si_p = NetProtocolHelper.GetSendPackage();
			si_p.Header.Messagid = NetMessageId.logicServer_notifyOffline;
			si_p.StartWrite();
			return si_p;
		}
		public override string ToString() {
			return "LogicServer.SC_notifyOffline { "
			+" }";
		}
	}
	private class ConnectRequest : IReceiveMessage
    {
		internal string token;
		internal string logicServerId;
		internal string gameServerId;
        public void FromPackage(ReceivePackage package)
		{
			SInputStream _in = package.InputStream;
            token = _in.HasRemaining() ? _in.Read_string() : default;
            logicServerId = _in.HasRemaining() ? _in.Read_string() : default;
            gameServerId = _in.HasRemaining() ? _in.Read_string() : default;
		}
        public int GetMessageId() { return NetMessageId.logicServer_connect; }
        public override string ToString()
        {
            return "LogicServer.connect"+ ", token="+ token+ ", logicServerId="+ logicServerId+ ", gameServerId="+ gameServerId;
        }
    }
	private class ReconnectRequest : IReceiveMessage
    {
		internal string reconnectToken;
		internal int readMsgCount;
		internal string connectId;
        public void FromPackage(ReceivePackage package)
		{
			SInputStream _in = package.InputStream;
            reconnectToken = _in.HasRemaining() ? _in.Read_string() : default;
            readMsgCount = _in.HasRemaining() ? _in.Read_int() : default;
            connectId = _in.HasRemaining() ? _in.Read_string() : default;
		}
        public int GetMessageId() { return NetMessageId.logicServer_reconnect; }
        public override string ToString()
        {
            return "LogicServer.reconnect"+ ", reconnectToken="+ reconnectToken+ ", readMsgCount="+ readMsgCount+ ", connectId="+ connectId;
        }
    }
	private class PingRequest : IReceiveMessage
    {
        public void FromPackage(ReceivePackage package)
		{
			SInputStream _in = package.InputStream;
		}
        public int GetMessageId() { return NetMessageId.logicServer_ping; }
        public override string ToString()
        {
            return "LogicServer.ping";
        }
    }
	private class LogoutRequest : IReceiveMessage
    {
        public void FromPackage(ReceivePackage package)
		{
			SInputStream _in = package.InputStream;
		}
        public int GetMessageId() { return NetMessageId.logicServer_logout; }
        public override string ToString()
        {
            return "LogicServer.logout";
        }
    }
	}
#endregion
}